package controller;

import helper.Formatter;
import helper.UserSession;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import model.CustomerDAO;
import model.FundDAO;
import model.FundHistoryDAO;
import model.FundHistoryDAOSQL;
import model.Model;
import model.PaymentDAOSQL;
import model.PositionDAO;
import model.TransactionDAO;
import model.TransactionDAOSQL;
import databeans.Customer;
import databeans.Employee;
import databeans.Fund;
import databeans.FundHistory;
import databeans.Position;

public class EmployeeExecuteTransitionAction extends Action{
    private FundDAO fundDAO;
    private FundHistoryDAO fundHistoryDAO;
    private FundHistoryDAOSQL fundHistoryDAOSQL;
    private TransactionDAO transactionDAO;
    private TransactionDAOSQL transactionDAOSQL;
    private CustomerDAO customerDAO;
    private PositionDAO positionDAO;
    private PaymentDAOSQL paymentDAOSQL;

    public EmployeeExecuteTransitionAction(Model model) {
        fundDAO = model.getFundDAO();
        fundHistoryDAO = model.getFundHistoryDAO();
        fundHistoryDAOSQL = model.getFundHistoryDAOSQL();
        transactionDAO = model.getTransactionDAO();
        transactionDAOSQL = model.getTransactionDAOSQL();
        customerDAO = model.getCustomerDAO();
        positionDAO = model.getPositoinDAO();
        paymentDAOSQL = model.getPaymentDAOSQL();
    }
    
    public String getName() {
        return "employeeExecuteTransition.do";
    }
    

    public String perform(HttpServletRequest request) {
        //ATTENTION
        // define target page
        String loginPage = "employee/employee-login.jsp";
        //String originPage = "employee/employee-transition-form.jsp";
        String originPage = "employee/transition-day.jsp"; 
        
        //set the employee
        Employee employee = null;
        Customer customer = null;
        
        //errors and messages will be stored here
        //resetting those containers
        List<String> errors = new ArrayList<String>();
        List<String> messages = new ArrayList<String>();
   
        //define the error and message
        request.setAttribute("errors", errors);
        request.setAttribute("messages", messages);
        request.setAttribute("page", "transition-day");
        
        //check if employee has been logged in
        //request.getSession() will return the current session and if one does not exist, a new session will be cretaed.
        //request.getSession(true) will return the current session if one exists, if one doesn't exits a new one will be created.
        //So there is actually no difference between the two methods HOWEVER, if you use request.getSession(false), it will return the current session if one exists and if one DOES NOT exist a new one will NOT be cretaed.
        employee = UserSession.getLoggedInEmployee(request);
        if (employee == null) {
            errors.add("You need to log in");
            return loginPage ;
        }
        
        //check if customer has actually logged in
        customer = UserSession.getLoggedInCustomer(request);
        if (customer != null) {
            request = UserSession.removeCustomerFromSession(request);
            errors.add("This section is closed for customer");
            return loginPage;
        }
        
        try {
        	
            //Get all the funds
        	Fund [] fundsList = fundDAO.getFunds();
        	System.out.println("Fundslist id1:"+fundsList[0].getFundID());
        	//Get all the latest prices for all the funds
        	double[] fundsPrices = new double[fundsList.length];
        	System.out.println("Fundslist lenght:"+fundsList.length);
        	//DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
        	//Date d1 = new Date();
        	for (int a=0;a<fundsList.length;a++) {
        		fundsPrices[a] = Double.parseDouble(Formatter.prepCashToView(fundHistoryDAOSQL.getLatestPrice(fundsList[a].getFundID()).getPrice()));
        		//Date d2 = fundHistoryDAOSQL.getLatestPrice(fundsList[a].getFundID()).getPriceDate();
        		//if(d2.after(d1))
        		//	d1 = d2;
        	}
        	/*
        	Calendar first = null, second;
        	second = Calendar.getInstance();
        	first.setTime(d1);
        	TimeUnit units = null;        	
        	long minDate = units.convert(second.getTimeInMillis()- first.getTimeInMillis(), TimeUnit.MILLISECONDS);
        	System.out.println("Days before date = " + minDate);
        	
        	System.out.println("2");
        	//Set the attributes for the page
        	request.setAttribute("minDate", minDate);*/ 
        	request.setAttribute("fundsList", fundsList);
        	request.setAttribute("fundsPrices", fundsPrices);
        	
        	String date = fundHistoryDAOSQL.getLatestDateString();
        	request.setAttribute("fundsDateOfLastTransaction", date);
        	System.out.println("date = " + date);
        	
        	SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");  
			Calendar calD=Calendar.getInstance();
		    calD.setTime(df.parse(date));
		    calD.add(Calendar.DATE, +1);
		    
		    int day = calD.get(Calendar.DATE);
            int month = calD.get(Calendar.MONTH);
            int year = calD.get(Calendar.YEAR);
            
		    date = String.valueOf(year) + "-" + String.valueOf(month) + "-" + String.valueOf(day);
	
		    System.out.println("date +1 = " + date);
		    
        	String[] minD = date.split("-");
        	request.setAttribute("minD", minD);
        	
        	System.out.println("3...Date:"+fundHistoryDAOSQL.getLatestDateString());
            // check for get or post request
            // if there is no parameter passed, return to origin page
            String requestType = request.getParameter("Submit");
        	
            if (requestType == null) {
                //messages.add("To transition, please fill up all the new prices");
                return originPage;     
            } else { 
            	System.out.println("GOT FORM REQUEST");
	            // get the total number of funds
	            int totalFunds = fundDAO.getNoOfFunds();
	            System.out.println("totalFunds = " + totalFunds);
	            String transDate = (String)request.getParameter("transDate");
	            System.out.println("transDate = " + transDate);
	            
	            //strictly for just populating the prices submitted
                String[] errorPrices = new String[totalFunds];
                for (int a=0; a<totalFunds; a++) {
                	errorPrices[a] = request.getParameter("txtNewFundPrice"+fundsList[a].getFundID());
                }
                request.setAttribute("fundsErrorPrices", errorPrices);
	            
	            
	            if (transDate.equals("") || transDate==null) {
	                errors.add("Date field cannot be empty. Please choose a Date");
	                return originPage;
	            }
	            
            	//request.getParameterValues for array of inputs
	            String tempPriceData = null;
	            String priceUpdateInfo = "Prices updated:<br />";
	            long originalPriceData;
	            //get date time
            	SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss");
            	Date d = new Date();
            	
            	DateFormat dfm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            	Date tempDate = dfm.parse(transDate+" "+timeFormat.format(d.getTime()));
            	Calendar cal=Calendar.getInstance();
                cal.setTime(tempDate);
                System.out.println("cal = " + cal.toString());
                
	            // validate the input
	            for (int a=0; a<totalFunds; a++) {
	            	System.out.println(fundsList[a].getFundID());
	            	System.out.println("txtNewFundPrice"+fundsList[a].getFundID());
	            	tempPriceData = request.getParameter("txtNewFundPrice"+fundsList[a].getFundID());
	            	originalPriceData = fundHistoryDAOSQL.getLatestPrice(fundsList[a].getFundID()).getPrice();
	            	
	            	priceUpdateInfo = priceUpdateInfo + "  Original Price = <b>$" + Formatter.prepCashToView(originalPriceData) + "</b>,     Current Price = <b>$" + Formatter.prepCashToView(Formatter.prepCashFromView(tempPriceData)) + "</b> <br />";
	            	System.out.println(priceUpdateInfo);
	            	if (tempPriceData.trim().equals("") || tempPriceData==null) {
		                errors.add("Price is missing for some Funds. Please check.");
		                return originPage;
		            }
	            	
	            	
	                //validate the input
	                if (tempPriceData.trim().equals("")) {
	                    errors.add("New prices for some funds field are missing. Please check");
	                    return originPage;
	                }
	                
	                try {
	                    Double.parseDouble(tempPriceData);
	                }
	                catch(NumberFormatException nFE) {
	                    errors.add("Invalid input for fund prices. Please check");
	                    return originPage;
	                }
	                
	                //check if double value inputted is A double
	                if (!Formatter.isDouble(tempPriceData)){
	                    //messages.add("You must input a number in amount field");
	                    errors.add("Invalid input in Amount field. Please check.");
	                    return originPage;
	                }
	                
	                //check if double has 2 decimal place
	                if(Formatter.numberOfDecimal(tempPriceData)>2) {
	                    errors.add("CFA only tracks amount up to two decimal place. Please enter a valid amount");
	                    //errors.add("Accuracy could not be captured");
	                    return originPage;
	                }
	                
	                //ensure no negative number
	                if ( Double.parseDouble(tempPriceData) <= 0.00 ){
	                    //messages.add("The amount should not be negative");
	                    errors.add("Invalid input for fund price. Please check.");
	                    return originPage;
	                }
	            	
	                
	                //ensure not too much check
	                if ( Double.parseDouble(tempPriceData) > 1000000000000.00 ){
	                    errors.add("The number you put is too large. ");
	                    return originPage;
	                }
	            	
	            	
	            	
	            	//validate that date is in the future
	            	Date dateToCheck = fundHistoryDAOSQL.getLatestPrice(fundsList[a].getFundID()).getPriceDate();
	            	//System.out.println("dateToCheck for fund ID= "+fundsList[a].getFundID() + " is " + dateToCheck.toString());
	            	
	            	Calendar calDB=Calendar.getInstance();
	            	calDB.setTime(dateToCheck);
	            	System.out.println("date in DB           = " + calDB);
	            	System.out.println("date Input from form = " + cal);
	            	System.out.println("");
	            	if (calDB.after(cal)) {
	   	                errors.add("Date is before the last entered Transition Day. Please check");
		                return originPage;
	            	}else
	            		System.out.println("Date is OK");
	            	
	            	//update prices
	            	boolean gotDuplicates = fundHistoryDAOSQL.checkDuplicates(fundsList[a].getFundID(), cal);
	            	if (!gotDuplicates) {
	            		FundHistory toUpdate = new FundHistory(fundsList[a].getFundID(), tempDate, Formatter.prepCashFromView(tempPriceData));
	            		fundHistoryDAO.create(toUpdate);
	            		System.out.println("Fund history Updated");
	            	} else {
	            		errors.add("Transition data for this day already exists. Please choose a later date.");
		                return originPage;
	            	}
	            }
	            messages.add("Transition Day Succesfully saved.");
	            /*
                //validate that date is in the future
                for (int a=0;a<fundsList.length;a++) {
	            	
	        	}
	            
	            //update prices
	            for (int a=0;a<totalFunds;a++) {
	            	//String tempPriceData = request.getParameter("txtNewFundPrice"+fundsList[a].getFundID());
	            	//System.out.println(tempPriceData);
	            	
	            	
	            }*/ 
	            
	            //process orders sequentially
	            //get all undone transactions
	            databeans.Transaction[] list = transactionDAOSQL.getUndoneTransactions();
	            System.out.println(list.length+" transactions found.");
	            double noOfShares, custShares;
	            for (int a=0;a<list.length;a++) {
	            	//get the latest fund history (which should be the date entered)
	            	FundHistory tempFH = fundHistoryDAOSQL.lookup(list[a].getFundID(), cal);
	            	
	            	//to show that a transaction has been executed, you need to update these:
	            	// -shares (for buy orders)
	            	// -amount (for sell orders)
	            	// -executeDate (for all)
	            	// -isSuccess (for all)
	            	
	            	if (list[a].getTransactionType().equals(databeans.Transaction.BUY_ORDER)) {
	            		//do buy order
	            		System.out.println("Order: "+list[a].getTransactionType());
	            		long tempTransactionAmount = list[a].getAmount() * 1000;
	            		long tempFHPrice = tempFH.getPrice();
	            		long tempNoOfShares = tempTransactionAmount / tempFHPrice;
	            		
	            		System.out.println(a + " temptransaction " + tempTransactionAmount);
	            		System.out.println(a + " tempFHprice  "+ tempFHPrice);
	            	    System.out.println(a + " tempNoOfShares  "+ tempNoOfShares);
                        
                        
	            		
	            		noOfShares = list[a].getAmount()/tempFH.getPrice();

	            		//update transaction (shares derived)
	            		list[a].setShares(tempNoOfShares );
	            		
	            		System.out.println(a + "list a getshares tempnoofshares " + list[a].getShares());
	            		
	            		//deduct from customer cash balance accordingly
	            		//this part should not be reachable if validation for buy and sell are good
		            	if (customerDAO.deductCash(list[a].getCustomerID(), list[a].getAmount())==false) {
		            		messages.add("Your cash balance is insufficient");
			                errors.add("Please contact us to resolve this.");
			                return originPage;
		            	}
		            	
		            	//does customer already have an existing position? if so, add to it, if not, create it
		            	Position testPosition = positionDAO.getPosition(list[a].getCustomerID(),list[a].getFundID());
		            	if (testPosition!=null) {
		            		//add to position
		            		testPosition.setShares(testPosition.getShares()+tempNoOfShares);
		            		positionDAO.update(testPosition);
		            	} else {
		            		//create position
		            		positionDAO.create(new Position(list[a].getCustomerID(),list[a].getFundID(),tempNoOfShares));
		            	}

	            	} else if (list[a].getTransactionType().compareTo(databeans.Transaction.SELL_ORDER)==0) {
	            		//do sell order
	            		System.out.println("Order: "+list[a].getTransactionType());
	            		custShares = positionDAO.getPosition(list[a].getCustomerID(), list[a].getFundID()).getShares();
	            		long tempCustShares = positionDAO.getPosition(list[a].getCustomerID(), list[a].getFundID()).getShares();
	            		long tempNoOfShares = tempCustShares - list[a].getShares();
	            		noOfShares = custShares - list[a].getShares();
	            		
	                    System.out.println(a + " custShares " + custShares);
                        System.out.println(a + " tempCustShares  "+ tempCustShares);
                        System.out.println(a + " tempNoOfShares  "+ tempNoOfShares);
                        
                        
	            		
	            		//update customer's new position or delete it if it's 0
	            		if (tempNoOfShares>=0){
	            			positionDAO.update(new Position(list[a].getCustomerID(),list[a].getFundID(),tempNoOfShares));
	            		} else {
	            			positionDAO.delete(list[a].getCustomerID(),list[a].getFundID());
	            		}
	            		
	            		//update transaction (cash derived)
	            		list[a].setAmount(list[a].getShares()*tempFH.getPrice()/1000);
	            		System.out.println(a + " list[a].getAmount() " + list[a].getAmount());
	            		System.out.println(a + " tempFH.getPrice() " + tempFH.getPrice());
	            		
	            		
	            		//add to customer cash balance
	            		customerDAO.addCash(list[a].getCustomerID(), list[a].getAmount());
		            	//update customer position
	            		
	            	} else if (list[a].getTransactionType().compareTo(databeans.Transaction.EXCHANGE_SELL_ORDER)==0) {
	            		//do exchange order
	            		//do the sell part
	            		System.out.println("Order: "+list[a].getTransactionType());
	            		custShares = positionDAO.getPosition(list[a].getCustomerID(), list[a].getFundID()).getShares();
	            		long tempCustShares = positionDAO.getPosition(list[a].getCustomerID(), list[a].getFundID()).getShares();
	            		long tempNoOfShares = tempCustShares - list[a].getShares();
	            		noOfShares = custShares - list[a].getShares();

	            		//update customer's new position or delete it if it's 0
	            		if (tempNoOfShares>=0){
	            			positionDAO.update(new Position(list[a].getCustomerID(),list[a].getFundID(),tempNoOfShares));	
	            		} else {
	            			positionDAO.delete(list[a].getCustomerID(),list[a].getFundID());
	            		}
	            		//update transaction (cash derived)
	            		double cashDerived = list[a].getShares()*tempFH.getPrice();
	            		long tempCashDerived = list[a].getShares()*tempFH.getPrice()/1000;
	            		list[a].setAmount(tempCashDerived);

	            		//using the cash, do the buy part
	            			            		
	            		//**********now do the buy part
	            		//get the id of the corresponding transaction and find it
	            		System.out.println("Looking for matching id:"+list[a].getCorrespondingTransactionID());
	            		databeans.Transaction matchingExchangeBuyTransaction = transactionDAOSQL.getMatchingTransaction(list[a].getCorrespondingTransactionID());
	            		FundHistory matchedFH = fundHistoryDAOSQL.lookup(matchingExchangeBuyTransaction.getFundID());
	            		System.out.println("Order: "+matchingExchangeBuyTransaction.getTransactionType());
	            		long tempNoOfShares2 = tempCashDerived *1000 / matchedFH.getPrice();
	            		System.out.println("tempcashderived = " + tempCashDerived + " matchedFH.price()" + matchedFH.getPrice());
	            		noOfShares = cashDerived/matchedFH.getPrice();
	            		//update transaction (shares derived)
	            		System.out.println("Mickey Exchange Buy No of shares:"+tempNoOfShares2);
	            		matchingExchangeBuyTransaction.setShares(tempNoOfShares2);
	            		matchingExchangeBuyTransaction.setExecuteDate(tempDate);

	            		transactionDAO.update(matchingExchangeBuyTransaction);	
	            		
	            		//does customer already have an existing position? if so, add to it, if not, create it
		            	Position testPosition = positionDAO.getPosition(list[a].getCustomerID(),list[a].getFundID());
		            	if (testPosition!=null) {
		            		//add to position
		            		testPosition.setShares(testPosition.getShares()+tempNoOfShares2);
		            		positionDAO.update(testPosition);
		            	} else {
		            		//create position
		            		positionDAO.create(new Position(list[a].getCustomerID(),list[a].getFundID(),tempNoOfShares2));
		            	}
	            	}
	            	
	            	if (list[a].getTransactionType().compareTo(databeans.Transaction.EXCHANGE_BUY_ORDER)!=0) {
	            	    list[a].setExecuteDate(tempDate);
	            	    System.out.println("Updating transaction...");
	            	    transactionDAO.update(list[a]);
	            	    System.out.println("---- Transaction updated ----");
	            	}
	            }
	            messages.add("All pending transactions have been updated.");
	            
	            
	            //Perform payments
	            //execute all undone payments
	            paymentDAOSQL.approveAllPendingPayments();
	            //databeans.Payment[] depositList = paymentDAO.getAllPendingDepositPayments();
	            //databeans.Payment[] withdrawalList = paymentDAO.getAllPendingWithdrawalPayments();
	            
	            
	            
	            //Get all the funds...AGAIN
	        	fundsList = fundDAO.getFunds();
	        	//Get all the latest prices for all the funds
	        	fundsPrices = new double[fundsList.length];
	        	for (int a=0;a<fundsList.length;a++) {
	        		//fundsPrices[a] = fundHistoryDAOSQL.getLatestPrice(fundsList[a].getFundID()).getPrice();
	        		fundsPrices[a] = Double.parseDouble(Formatter.prepCashToView(fundHistoryDAOSQL.getLatestPrice(fundsList[a].getFundID()).getPrice()));
	                
	        	}
	        	
	        	System.out.println("Funds info retrieved");
	        	//Feedback price changes to employee
	        	
	        	messages.add(priceUpdateInfo);
	        	//Set the attributes for the page
	        	request.setAttribute("mindDate", "");
	        	request.setAttribute("fundsList", fundsList);
	        	request.setAttribute("fundsPrices", fundsPrices);
	        	
	        	date = fundHistoryDAOSQL.getLatestDateString();
	        	calD.setTime(df.parse(date));
			    calD.add(Calendar.DATE, +1);
			    
			    day = calD.get(Calendar.DATE);
	            month = calD.get(Calendar.MONTH);
	            year = calD.get(Calendar.YEAR);
	            
			    date = String.valueOf(year) + "-" + String.valueOf(month) + "-" + String.valueOf(day);
			    
	        	request.setAttribute("fundsDateOfLastTransaction", date);
	        	
	        	minD = date.split("-");
	        	request.setAttribute("minD", minD);
	        	
	        	request.setAttribute("fundsErrorPrices", null);
	            
	            // tell employee transition is successful
	            //return successPage;
	            return originPage;
            }
        } catch (Exception e) {
            //errors.add(e.getMessage());
            return originPage;
        }

    }
}